
import { REACT_ELEMENT, REACT_FORWARD_REF, REACT_FRAGMENT, REACT_CONTEXT, REACT_PROVIDER, REACT_MEMO } from './element'
import { wrapToVDom, shallowEqual } from "./utils";
import Component from './Component'
import * as hooks from './react-dom'

/**
 *  虚拟dom属性处理 为props
 * @param {*} type  ele类型
 * @param {*} config ele属性
 * @param  {...any} children  子元素
 * @returns 
 */
function createElement(type, config, ...children) {
    let key;
    let ref;
    if (config) {
        key = config.key
        delete config.key
        ref = config.ref
        delete config.ref
        delete config._owner
        delete config.__self
        delete config.__source
    }

    let props = { ...config }

    if (children.length === 1) {
        props.children = wrapToVDom(children[0])
    } else if (children.length === 0) {
        props.children = null
    } else {
        props.children = children.map(wrapToVDom) // 文本节点添加类型
    }

    return {
        $$typeof: REACT_ELEMENT,
        key,
        ref,
        type,
        props
    }
}

/**
 *  创建ref
 * @returns 
 */
function createRef() {
    return { current: null }
}

/**
 * 
 * @param {函数组件} render 
 */
function forwardRef(render) {
    return {
        $$typeof: REACT_FORWARD_REF,
        render
    }
}

/**
 * context Provider Consumer
 */
function createContext() {
    const context = {
        $$typeof: REACT_CONTEXT,
        _currentValue: undefined,

    }
    const Provider = {
        $$typeof: REACT_PROVIDER,
        _context: context
    }
    const Consumer = {
        $$typeof: REACT_CONTEXT,
        _context: context
    }
    context.Provider = Provider
    context.Consumer = Consumer
    return context
}

/**
 * clone一个jsx 设置newChildren时使用newChildren 否则复用老children
 * 
 * @param {被clone的老节点} element 
 * @param {需要合并的新属性} newProps 
 * @param  {新的子元素} newChildren 
 * @returns  合并后的新虚拟dom
 */
function cloneElement(element, newProps, ...newChildren) {
    let children = element.props?.children || [] // 拿到jsx子元素
    if (newChildren.length > 0) {
        children = newChildren.map(wrapToVDom) // 循环处理文本节点
    }
    if (children.length === 1) { // 一个child时 为{} 格式
        children = children[0]
    }
    let props = { ...element.props, ...newProps }
    return { ...element, props }
}

class PureComponent extends Component {
    shouldComponentUpdate(newProps, newState) {
        return !shallowEqual(this.props, newProps) || !shallowEqual(this.state, newState)
    }
}


function memo(FunctionComponent, compare = shallowEqual) {
    return {
        $$typeof: REACT_MEMO,
        type: FunctionComponent,
        compare
    }
}

function useContext(context) {
    return context._currentValue
}

const React = {
    createElement,
    Component,
    createRef,
    forwardRef,
    Fragment: REACT_FRAGMENT,
    createContext,
    cloneElement,
    PureComponent,
    memo,
    useContext,
    ...hooks
}

export default React